<!DOCTYPE html>
<!--
File:      implementation.html
Author:    Henry Feild
Date:      March 2013
Purpose:   Gives instructions about how to create a CLRM package.

%%COPYRIGHT%%

Version: %%VERSION%%
-->
<html>
<head>
    <script src="js/external/jquery.min.js"></script>
    <script src="js/content-page.js"></script>
</head>
<body>
<div class="toc">
    <h2>Contents</h2>
    <ul>
        <!-- <li><a href="#implement">Implementing a CrowdLogger Remote Module</a> -->
        <li><a href="#implement:what-clrm-consists-of"
            >What a CLRM Package Consists of</a>
        <li><a href="#implement:core-module-structure"
            >The Structure of the Core Module Code</a>
        <li><a href="#implement:referencing-resources"
            >Referencing Module Resources</a>
        <li><a href="#implement:auto-packaging">Automatic Packaging</a> 
    </ul>
</div>

<h1>Implementing a CrowdLogger Remote Module</h1>

<p>
This page will contain information about implementing a module, including the
directory structure and some simple examples. It will also contain an overview
of the API. 
</p>

<p>
<span class="highlight"><b>Note:</b> While many of the sections below
go into the details of the underlying CLRM format, there is an automatic
method for generating the CLRM JSON description, which is discussed in the
<a href="#implement:auto-packaging">Automatic Packaging</a> section.
</span>
</p>

<a name="what-clrm-consists-of"></a>
<h2>What a CLRM Package Consists of</h2>
<p>
A CLRM Package is a JSON object with the following fields:
</p>

<table>
    <tr>
        <th>Field</th> <th width="125px">Type</th> <th>Description</th> 
    </tr><tr>
        <td><code>metadata</code></td>
        <td>object</td>
        <td>Contains information about the package, such as id, as well as
            display information (e.g., name and description). 
            <a href="#implement:metadata">We describe metadata further here</a>.
        </td>
    </tr><tr>
        <td><code>module</code></td>
        <td>string</td>
        <td>The core module code. 
            <a href="#implement:core-module-structure">This must adhere to the 
            structure described below</a>. This code will be evaluated using
            <code>eval()</code> and will have access to the package object
            (so resources can be accessed) as well as the CLRM API.
        </td>
    </tr><tr>
        <td><code>html</code></td>
        <td>map to strings</td>
        <td>A map of HTML document names to the document content. Each of these
            virtual files can be loaded into a window when needed. They can
            reference other sources from this object, including JavaScript 
            (see <code>js</code>), CSS (see <code>css</code>), and other HTML
            content. See the <a href="#implement:referencing-resources">
            Referencing Module Resources</a> section for more information about
            how to link to these resources.
        </td>
    </tr><tr>
        <td><code>js</code></td>
        <td>map to strings</td>
        <td>A map of JavaScript document names to the script content. The
            content will be inserted within <code>&lt;script&gt;</code> tags
            in the header of HTML documents that reference it.
        </td>
    </tr><tr>
        <td><code>css</code></td>
        <td>map to strings</td>
        <td>A map of CSS document names to the style sheet content. The
            content will be inserted within <code>&lt;style&gt;</code> tags
            in the header of HTML documents that reference it.
        </td>
    </tr><tr>
        <td><code>misc</code></td>
        <td>map to strings</td>
        <td>A map of miscellaneous resources names to content. When used in
            conjunction with a resource reference, the
            content will replace <code>::CLRMMISC:name</code> occurrences in,
            e.g., HTML documents.
        </td>
    </tr>
</table>

<a name="metadata"></a>
<h3>Metadata</h3>
<table>
    <tr>
        <th>Field</th> <th width="125px">Type</th> <th>Description</th>
    </tr><tr>
        <td><code>clrmid</code></td>
        <td>string</td>
        <td>The id of the CLRM. This should be unique from other CLRMs, but
            consistent across versions of the same CLRM.
        </td>
    </tr><tr>
        <td><code>name</code></td>
        <td>string</td>
        <td>The display name of the CLRM. This will be shown to users.</td>
    </tr><tr>
        <td><code>version</code></td>
        <td>string</td>
        <td>The version; should only consist of digits and decimals. The 
            following are valid versions: <code>1.0</code>, 
            <code>5.4.005.3</code>, <code>2</code>. Version comparisons work
            left to right, parsing each block (between dots) as an int and
            comparing corresponding blocks. Missing blocks are assumed 0. 
            E.g., <code>5.4.005.3 &gt; 5.4</code>, 
            <code>6 &gt; 5.4.005.3</code>, and 
            <code>5.01 == 5.01.00.0000.0</code>.
        </td>
    </tr><tr>
        <td><code>categories</code></td>
        <td>array of strings</td>
        <td>The CLRM categories this CLRM falls into. Right now, there is no
            real divide between categories except for the connotations they 
            carry and that they are divided on the CLRM Library page.
            Can be any and all of the following: 
            <ul>
                <li><code>app</code>
                    <ul>
                        an app; this should not be tied to an IRB protocol or
                        other study-like aspects. Examples of apps include
                        search visualizations and bookmarkers. Many of these
                        will not require uploading information (unless an
                        algorithm requires it).
                    </ul>
                <li><code>study</code>
                    <ul>
                        a study module; this will likely involve an IRB 
                        informed consent form and will need to upload certain
                        amounts of information.
                    </ul>
            </ul>
        </td>
    </tr><tr>
        <td><code>logoURL</code></td>
        <td>string</td>
        <td>The URL of an image to display to the user on the CLRM library
            page. This is not required, but will make the app look prettier.
            Images are scaled to 30&times;30 pixels.
        </td>
    </tr><tr>
        <td><code>packageURL</code></td>
        <td>string</td>
        <td>The URL where the corresponding CLRM Package can be found.
        </td>
    </tr><tr>
        <td><code>description</code></td>
        <td>string</td>
        <td>A long description of the CLRM. This will be displayed to users
            before the install the CLRM.
        </td>
    </tr><tr>
        <td><code>permissions</code></td>
        <td>array of strings</td>
        <td>A list of the APIs this CLRM requires access to. This will eventually be
            shown to users before they are able to install the CLRM (currently, it's ignored). Valid values are:
            <ul>
                <li><code>userdata</code></li>
                <li><code>ui</code></li>
                <li><code>storage</code></li>
                <li><code>privacy</code></li>
                <li><code>serveraccess</code></li>
                <li><code>globaldata</code></li>
            </ul>
        </td>
    </tr><tr>
        <td><code>minCLVersion</code></td>
        <td>string</td>
        <td>The minimum CrowdLogger version, e.g., <code>2.0.1</code></td>
    </tr>
</table>

<!-- <pre class="prettyprint">
{
    string:
}
</pre> -->

<a name="core-module-structure"></a>
<h2>The Structure of the Core Module Code</h2>

<p>
The core module is the JavaScript stored under the <code>module</code> key in 
the CRLM Package. At a minimum, core modules must:
</p>

<ul>
    <li>contain a global function named <code>RemoteModule</code> that takes
        two parameters: the containing CLRM Package and a copy of the CLRM API.
        <span class="highlight">Note: this should be the only thing you add to
            the global space!</span>
    <li>make the following methods available within the 
        <code>RemoteModule</code> instance:
    <ul>
        <li>{function} <code>init</code> 
        <ul>This should initialize the module.
            <span class="highlight">Nothing should be initialized outside of 
            the <code>init</code> function! 
            (<a href="#implement:note-on-init">see this note</a>)</span>
        </ul>
        <li>{function} <code>unload</code>
        <ul>
            Should accept the following parameters:
            <ul>
                <li>{string} <code>reason</code>
                    <ul>Why the module is being unloaded:
                        <li><code>'shutdown'</code>&mdash;a routine shutdown
                        <li><code>'disable'</code>&mdash;the user or extension
                            want to disable, but not uninstall, the CLRM
                        <li><code>'uninstall'</code>&mdash;the user or extension
                            want to completely remove the CLRM; all stored data
                            should be removed
                        <li><code>'newversion'</code>&mdash;unloading as a 
                            precursor to installing a new version
                    </ul>
                <li>{function} oncomplete
                    <ul>Invoke when unloading has successfully completed.</ul>
                <li>{function} onerror
                    <ul>Invoke if a error is encountered.</ul>
            </ul>
        </ul>
        <li>{function} <code>configure</code>
        <ul>
            Takes no parameters; should open the settings/configuration window
            for the CLRM.
        </ul>
        <li>{function} <code>open</code>
        <ul>
            Takes no parameters; should open the main interface for the CLRM.
        </ul>
        <li>{function} <code>getMessage</code>
        <ul>
            Takes no parameters; Should return a string which will be displayed
            to users on the CrowdLogger Status Page. This string may contain 
            HTML.
        </ul>
        <li>{function} <code>isOkayToUpdate</code>
        <ul>
            Takes no parameters; should return a boolean: <code>true</code>
            if the CLRM is in a good spot to be updated, and <code>false</code>
            otherwise.
        </ul>
    </ul>
</ul>

<p>
The <code>RemoteModule</code> function will be invoked with the <code>new</code>
keyword and passed a copy of the containing CLRM Package and a copy of the 
CLRM API. E.g.,
</p>

<pre class="prettyprint">
function RemoteModule( clrmPackage, api ){
    this.id = 'My Module';
    this.unload = function(oncomplete){ 
        oncomplete(); 
    };
    this.init = function(){
        api.ui.alert('Hi!');
    };
}    
</pre>

<p>
For larger modules, you will likely want to split your code up across files  (of
course, these will have to be concatenated before being added to the CLRM
Package). For instances, you may want to define a <code>Model</code> class that
provides functionality to maintain a persistent model over user interactions. To
avoid adding this to the global name space, but still allow your
<code>RemoteModule</code> class access to it, you can modify
<code>RemoteModule.prototype</code>. For example:
</p>

<pre class="prettyprint">
// file1.js

var RemoteModule = function( clrmPackge, api ){
    this.id = "My Module";
    // <a href="http://stackoverflow.com/questions/4886632/what-does-var-that-this-mean-in-javascript">See this page for more info about var that = this.</a>
    var that = this;
    var model, view;
    
    this.init = function(){
        model = new that.Model(api);
        view = new that.View(api)
    };

    this.unload = function(oncomplete, onerror){
        // This save may happen asyncronously -- that is, when model.save
        // returns, the process of saving may still be occurring. So, we pass
        // oncomplete along so that whatever code uses it last can invoke it.
        model.save(oncomplete);
    };

    this.getMessage = function(){
        return 'Version '+ clrmPackage.metadata.version +
            '&lt;br/&gt;&lt;span style="color: red"&gt;This is just a demonstration message, '+
            'please ignore.&lt;/span&gt;';
    };

    this.open = function(){
        view.launchMain();
    };

    this.configure = function(){
        view.launchSettings();
    };

    this.isOkayToUpdate = function(){
        return model.isIdle;
    };
}
</pre>

<pre class="prettyprint">
// file2.js

RemoteModule.prototype.Model = function(api){
    ...
    this.isIdle = false;
    ...
    this.save = function(oncomplete){
        ...
        // Somewhere oncomplete() is invoked.
        ...
    };
    ...
}

RemoteModule.prototype.View = function(api){
    ...
    this.launchMain = function(){
        api.ui.launchWindow('main.html');
    }; 
    ...
    this.launchSettings = function(){
        api.ui.launchWindow('settings.html');
    }
    ...
    <!--
    // Private variables.
    var that = this,
        DB_NAME = "mydb",
        DB_VERSION = 1;

    // Private function declarations.
    var init, processSE, processQuery;

    // Public variables.
    this.data = {
        seCounts: {
            TOTAL: 0
        },
        queryTermCounts: {
            TOTAL: 0
        }
    };

    // Public function declarations.
    this.save;

    // Private function definitions.
    // Initialize the listeners.
    init = function(){
        // Add listeners to some user activity...
        api.user.realtime.onSearch(function(search){
            processSE(search.se);
            processQuery(search.query);
        });
    }

    // Increments a search engines occurence.
    processSE = function(se){
        var curCount = that.data.seCounts[se] ? 
            that.data.seCounts[se] : 0;
        that.data.seCounts[se] = curCount + 1;
        that.data.seCounts.TOTAL += 1;
    }

    // Updates the counts for each term that occurs in the query.
    processQuery = function(query){
        var terms = query.toLower().split(/\s+/), term;
        for( term in terms ){
            var curCount = that.data.queryTermCounts[term] ? 
                that.data.queryTermCounts[term] : 0;
            that.data.queryTermCounts[term] = curCount + 1;
            that.data.queryTermCounts.TOTAL += 1;
        }
    }

    // Public function definitions.
    // Save the data.
    this.save = function(){
        api.user.db.write(DB_NAME, DB_VERSION, that.data);
    };

    // Called on initialization.
    init();
-->
}
</pre>

<a name="note-on-init"></a>
<h3>A note on <code>init</code></h3>
<p>
The reason we require that nothing occur outside of the <code>init</code>
function in the core <code>RemoteModule</code> object is that, if an older 
version of your CLRM is loaded, we need to invoke the <code>unload</code>
function of that older instance. This might involve removing listeners
and such from elements, saving data, etc. Your new code will likely want to
reattach those listeners, read in the saved data, etc., so it must wait until
the clean up is complete.
</p>



<a name="referencing-resources"></a>
<h2>Referencing Module Resources</h2>

<p>
Assuming the CLRM Package is stored in the variable <code>package</code>,
references are made in HTML content in the following way:
</p>

<table>
    <tr>
        <th>Pattern</th> <th>Description</th> 
    </tr><tr> 
        <td><code>::CLRMJS:name</code></td>
        <td>Gets replaced with 
            <code> &lt;script&gt;package.js[name]&lt;script&gt; </code>
        </td>
    </tr><tr>
        <td><code>::CLRMCSS:name</code></td>
        <td>Gets replaced with 
            <code> &lt;style&gt;package.css[name]&lt;style&gt; </code>
        </td>
    </tr><tr>
        <td><code>::CLRMMISC:name</code></td>
        <td>Gets replaced with 
            <code> package.misc[name] </code>
        </td>
    </tr>

</table>


<a name="auto-packaging"></a>
<h2>Automatic Packaging</h2> 

<p>
It's tedious and error prone to have to package a CLRM manually. Rather than
do that, you can feed the core CLRM script and a set of resources&mdash;HTML,
JavaScript, and CSS files&mdash;to the <code>clrm-package.rb</code> script (you can <a href="">download the latest version from Google code</a>.
This naive script does the following: 
</p>

<ol>
    <li>an empty package is made
    <li>the core module scripts are concatenated and added to the package under
        the <code>module</code> key
    <li>for each HTML resource, all linked CSS and JavaScript files in 
        <code>&lt;link&gt;</code> and <code>&lt;script&gt;</code> tags are
        added to the list of resources and are replaced with their references
        (see the <a href="#implement:referencing-resources">Referencing Module 
        Resources</a>section). E.g., this:
<pre class="prettyprint">
&lt;html&gt;
  &lt;head&gt;
    &lt;script src="myscript.js"&gt;&lt;/script&gt;
    &lt;link href="mystyle.css" rel="stylesheet" type="text/css"/&gt;
  &lt;/head&gt;
  &lt;body&gt;
  ...
  &lt;/body&gt;
&lt;/html&gt;
</pre> 
becomes:
<pre class="prettyprint">
&lt;html&gt;
  &lt;head&gt;
::CLRMJS:myscript.js
::CLRMCSS:mystyle.css
  &lt;/head&gt;
  &lt;body&gt;
  ...
  &lt;/body&gt;
&lt;/html&gt;
</pre>    
    <li>for each resource, it makes an entry in the corresponding map in the 
        package; each resources base filename is used as the key

</ol>



</body>
</html>